/*
 * 组织架构管理
 */

(function($){
    $(function(){

        var USERAGENT = navigator.userAgent.toLowerCase(),
            ISIE = USERAGENT.indexOf("msie") > 0,
            IEVERSION = ISIE ? USERAGENT.match(/msie ([\d.]+)/)[1] : null,
            ISIE6 = ISIE && IEVERSION == '6.0';
        var MINDMAP_MENU_TITLE = {'icon': '选择图标','add': '添加子节点', 'del': '删除该节点', 'edit': '编辑该节点', 'move-up': '向上移动', 'move-down': '向下移动'}


        /* 思维导图 */
        var mindmap = function(selector, options){
            this.options = $.extend(true, {}, mindmap.defaults, options || {});
            this.dom = {
                container : $(selector),
                mindmap: null
            };
            // 禁止选择文字
            $(selector).off('selectstart.md').on('selectstart.md', 'div[data-type="node"]>i[data-type="icon"], div[data-type="node"]>span[data-type="name"]', function(event){
                return false;
            });

            
            (function(jsonData){
                var tempData = {
                        id:'department',
                        name: ' + 添加部门',
                        level: 'department',
                    };
                if (jsonData.children && jsonData.children.length > 0) {
                    jsonData.children.push(tempData);
                }
                else{
                    jsonData.children = [tempData];
                }
            }(this.options.jsonData));

            // 渲染页面图形
            this.render.call(this);
            this.dom.container.data('data-mindmap', this);
        };

        /* 思维导图扩展对象 */
        mindmap.prototype = {
            _event: {
                onMenu: function(){
                    return;
                    var that = this,
                        $mindmap = this.dom.mindmap;
                    $mindmap.undelegate('div[data-type="node"]', 'hover');
                    $mindmap.delegate('div[data-type="node"]', 'hover', function(event) {
                        // 显示/隐藏节点菜单
                        if (event.type == 'mouseenter' && $(this).attr('data-status') != 'edit') {
                            that._delegation.showMenu.call(that, $(this));
                        }
                        else {
                            that._delegation.hideMenuIcon.call(that, $(this));
                        }
                    });
                },
                onEnd: function(){
                    var that = this,
                        endViewFN = (that.options.Event || {}).endViewFN || function(){},
                        $mindmap = this.dom.mindmap;
                    $mindmap.undelegate('div[data-haschildren="false"]', 'click');
                    $mindmap.delegate('div[data-haschildren="false"]', 'click', function(event) {
                        var nid = Number($(this).attr('data-id') || 0),
                            pnid = Number($(this).attr('data-pid') || 0),
                            jsonObject = that._data.get.call(that, nid, null) || {},
                            jsonData = $.extend({}, {'pid': pnid}, jsonObject.jsonData || {});
                        endViewFN.call(that, nid, jsonData)
                    });
                },
                onBranch: function(){
                    var that = this,
                        $mindmap = this.dom.mindmap;
                    $mindmap.undelegate('i[data-type="branch"]', 'click branch-onlychangedom');
                    $mindmap.delegate('i[data-type="branch"]', 'click branch-onlychangedom', function(event) {
                        var $branch = $(this),
                            isonlychangedom = event.type === 'branch-onlychangedom';
                        // 显示/隐藏节点分支
                        that._delegation.switchBranch.call(that, $branch, isonlychangedom);
                        return false;
                    });
                },
                onIcon: function(){
                    return;
                    var that = this,
                        $mindmap = that.dom.mindmap;
                    $mindmap.undelegate('i[data-type="icon"]', 'click');
                    $mindmap.delegate('i[data-type="icon"]', 'click', function(event) {
                        // 附加一个节点
                        that._delegation.showIcon.call(that, $(this));
                        return false;
                    });
                },
                onAdd: function(){
                    return;
                    var that = this,
                        $mindmap = that.dom.mindmap;
                    $mindmap.undelegate('i[data-type="add"]', 'click');
                    $mindmap.delegate('i[data-type="add"]', 'click', function(event) {
                        // 附加一个节点
                        that._delegation.add.call(that, $(this));
                        return false;
                    });
                },
                onEdit: function(){
                    return;
                    var that = this,
                        $mindmap = that.dom.mindmap;

                    // 双击节点
                    $mindmap.undelegate('div[data-type="node"]', 'dblclick');
                    $mindmap.delegate('div[data-type="node"]', 'dblclick', function(event) {
                        // 编辑一个节点
                        var $self = $(this),
                            nid = Number($self.attr('data-id') || 0);
                        that._delegation.edit.call(that, nid);
                        return false;
                    });
                    // 点击编辑按钮
                    $mindmap.undelegate('i[data-type="edit"]', 'click');
                    $mindmap.delegate('i[data-type="edit"]', 'click', function(event) {
                        // 编辑一个节点
                        var $self = $(this),
                            nid = Number($self.parent('div').attr('data-nid') || 0);
                        that._delegation.edit.call(that, nid);
                        return false;
                    });
                },
                onDelete: function(){
                    return;
                    var that = this,
                        $mindmap = that.dom.mindmap;
                    $mindmap.undelegate('i[data-type="del"]', 'click');
                    $mindmap.delegate('i[data-type="del"]', 'click', function(event) {
                        // 移除一个节点
                        that._delegation.remove.call(that, $(this));
                        return false;
                    });
                },
                onMove: function(){
                    return;
                    var that = this,
                        $mindmap = that.dom.mindmap;
                    $mindmap.undelegate('i[data-type^="move"]', 'click');
                    $mindmap.delegate('i[data-type^="move"]', 'click', function(event) {
                        // 上下移动节点
                        that._delegation.switchMove.call(that, $(this));
                        return false;
                    });
                },
                onDragDrop: function(){
                    return false;
                    var that = this,
                        $mindmap = this.dom.mindmap,
                        $nodes = $('div[data-type="node"]', $mindmap);
                    $nodes.draggable("destroy");
                    $nodes.droppable('enable');
                    $nodes.draggable({
                        cursor      : 'move',
                        distance    : 30,
                        helper      : function(event){
                            var $node = $(event.currentTarget || event.target),
                                $menu = $node.children('div[data-type="menu"]'),
                                $iconList = $node.children('div[data-type="icon-list"]');
                            $menu.add($iconList).remove();
                            return $node.clone();
                        },
                        cursor: "move",
                        cursorAt: { top: 16, left: 16 },
                        helper: function(event) {
                            var $node = $(event.currentTarget || event.target),
                                $icon = $node.children('i[data-type="icon"]'),
                                $name = $node.children('span[data-type="name"]'),
                                name = $.trim($name.text() || '');
                            return $('<div class="node-box ellipsis">' +
                                        //'<i class="box-icon">'+ $icon.html() +'</i>' +
                                        '<span class="box-text nowrap">'+ (function(){
                                            return name.length > 10 ? name.substring(0, 10) + '...' : name;
                                        }()) +'</span>' +
                                    '</div>');
                        },
                        opacity     : 0.8,
                        revert      : 'invalid',
                        revertDuration : 100,
                        snap        : 'div.node.expanded',
                        snapMode    : 'inner',
                        stack       : 'div[data-type="node"]'
                    });
                    
                    $nodes.droppable({
                        accept      : 'div[data-type="node"]',          
                        activeClass : 'drag-active',
                        hoverClass  : 'drop-hover'
                    });
                    
                    // Drag start event handler for nodes
                    $nodes.off('dragstart').on("dragstart", function handleDragStart(event, ui){
                        var $targetNode = $(this),
                            $targetTR = $targetNode.parent('td').parent('tr'),// 准目标节点
                            $childNodes = $targetNode;
                        if ($targetTR._isorigin()) {
                            $childNodes = $targetTR.parent('tbody').find('div[data-type="node"]');
                        }
                        $childNodes.droppable('disable');
                    });

                    // Drag stop event handler for nodes
                    $nodes.off("dragstop").on("dragstop", function handleDragStop(event, ui){
                        var $helper = ui.helper,
                            $sourceTR = $helper.parentsUntil('tr[data-status="unavailable"]').last('td').parent('tr');
                        // 移除源节点
                        $sourceTR.remove();
                        // 重新绑定拖拽事件
                        that._event.onDragDrop.call(that);
                        // 移除活动状态样式类
                        $nodes.removeClass('drag-active');
                    });
                
                    // Drop event handler for nodes
                    $nodes.off("drop").on("drop", function handleDropEvent(event, ui) {
                        // 拖拽节点
                        that._delegation.dragDrop.call(that, $(this), ui.draggable);
                    });
                },
                init: function(){
                    // 判断是否为预览状态
                    if (this.options.isView) {
                        this._event.onEnd.call(this);
                    }
                    else{
                        this._event.onMenu.call(this);
                        this._event.onIcon.call(this);
                        this._event.onAdd.call(this);
                        this._event.onEdit.call(this);
                        this._event.onDelete.call(this);
                        this._event.onMove.call(this);
                        this._event.onDragDrop.call(this);
                    }
                    this._event.onBranch.call(this);
                }
            },
            _delegation: {
                showMenu: function($node){
                    // 判断是否拖拽活动状态
                    if ($node.hasClass('drag-active')) {
                        return false;
                    };
                    var $childMenu = $node.children('div[data-type="menu"]'),
                        $childIconList = $node.children('div[data-type="icon-list"]'),
                        $menu = this._dom.createMenu.call(this, $node);
                    // 隐藏节点、嵌入节点、定位节点
                    $childMenu.add($childIconList).hide();
                    $node.append($menu);
                    $menu.css('width', $menu.width());
                    $menu.position({
                        of: $node,
                        my: 'right bottom',
                        at: 'right bottom',
                        offset: "0 20"
                    });
                },
                showIcon: function($icon){
                    var that = this,
                        $menu = $icon.parent('div'),
                        nid = Number($menu.attr('data-nid') || 0),
                        $node = that._dom.getBox.call(that, nid),
                        $iconList = $(that.options.Template.iconList),
                        commitFN = (this.options.CallBack || {}).commitFN || function(){},
                        updateIconFN = (this.options.CallBack || {}).updateIconFN || function(){};

                    $node.append($iconList);
                    $iconList.position({
                        of: $menu,
                        my: 'left top',
                        at: 'left bottom',
                        offset: (function(){
                            return ISIE6 ? '-2 -2': '0 -1';
                        }())
                    });
                    $iconList.on('click', 'i', function(){
                        var $icon = $node.children('i[data-type="icon"]'),
                            newicon = $('img', this).attr('src') || '';
                        var successFN = function(){
                            $icon.replaceWith(function(){
                                return that._dom.createIcon.call(that, newicon);
                            });
                            // 更新 JsonData
                            that._data.updateIcon.call(that, nid, newicon, null);
                            successFN = function(){};
                        };
                        // 执行提交模拟操作委托函数
                        commitFN.call(that, nid, function cloneJsonData(){
                            // 深度拷贝 JsonData
                            var _cloneJsonData = $.extend(true, {}, that.options.jsonData);
                            // 更新 JsonData
                            that._data.updateIcon.call(that, nid, newicon, _cloneJsonData);
                            // 返回克隆已更新数据
                            return _cloneJsonData;
                        }, successFN);

                        // 执行更新图标委托函数
                        updateIconFN.call(that, nid, newicon, successFN);
                    });
                },
                hideMenuIcon: function($node){
                    var $childMenu = $node.children('div[data-type="menu"]'),
                        $childIconList = $node.children('div[data-type="icon-list"]');
                    // 移除节点菜单
                    $childMenu.add($childIconList)
                    .remove();
                },
                switchBranch: function($branch, isonlychangedom){
                    var $originTR = $branch.parentsUntil('tbody').last('tr[data-type="origin"]'),
                        $node = $originTR.children('td').children('div[data-type="node"]'),
                        $nextTRs = $originTR.nextAll('tr'),
                        $originTBODY = $originTR.parent(),
                        that = this,
                        nid = Number($node.attr('data-id') || 0),
                        iscollapsed = Number($branch.attr('data-value') || 0) === 1,
                        commitFN = (this.options.CallBack || {}).commitFN || function(){},
                        updateCollapsedFN = (this.options.CallBack || {}).updateCollapsedFN || function(){},
                        successFN = function(){
                            if (iscollapsed) {
                                $branch.attr('data-value', 0);
                                $branch.removeClass('collapsed').addClass('expand');
                            }
                            else{
                                $branch.attr('data-value', 1);
                                $branch.removeClass('expand').addClass('collapsed');
                            }
                            // 切换显示和隐藏子节点
                            $nextTRs.toggleClass('hidden', !iscollapsed);
                            // 兼容 IE 6, 如果使用此段代码，在ie6下可能会出现截屏，如果不适用，可能会出现其他问题
                            // $originTBODY.addClass('hidden').removeClass('hidden');
                            // 判断是否为仅仅只更改dom或预览状态
                            if (!isonlychangedom && !that.options.isView) {
                                // 更新 JsonData
                                that._data.updateCollapsed.call(that, nid, !iscollapsed, null);
                            }
                            successFN = function(){};
                        };
                    // 判断是否为仅仅只更改dom或预览状态
                    if (!!isonlychangedom || that.options.isView) {
                        successFN(nid);
                    }
                    else{
                        // 执行提交模拟操作委托函数
                        commitFN.call(that, nid, function cloneJsonData(){
                            // 深度拷贝 JsonData
                            var _cloneJsonData = $.extend(true, {}, that.options.jsonData);
                            // 更新 JsonData
                            that._data.updateCollapsed.call(that, nid, !iscollapsed, _cloneJsonData);
                            // 返回克隆已更新数据
                            return _cloneJsonData;
                        }, successFN);

                        // 执行更新折叠状态委托函数
                        updateCollapsedFN.call(that, nid, !iscollapsed, successFN);
                    }
                },
                add: function(nid, childJsonData){
                    var that = this,
                        addFN = (that.options.CallBack || {}).addFN || function(){},
                        //nid = Number($add.parent('div').attr('data-nid') || 0),
                        $mindmap = that.dom.mindmap,
                        $node = that._dom.getBox.call(that, nid),
                        $targetTR = $node.parent('td').parent('tr');// 准目标节点
                        
                    // 执行添加一个子节点的接口函数
                    addFN.call(that, nid, function(nid, _childJsonData){
                        // 判断目标节点是否为源节点
                        if($targetTR._isorigin()){
                            var $originTR = $targetTR,// 准目标源节点
                                $originTBODY = $originTR.parent('tbody'),//源节点的父节点
                                $originTRTwoTDs = $originTR.children('td').slice(0, 2),// 源节点的前两个子节点
                                $branch = $originTRTwoTDs.eq(1).find('div.node-branch.none');// 折叠
                                //$branch = $originTRTwoTDs.eq(1).find('i[data-type="branch"][data-value="1"]');// 折叠
                            
                            $branch.removeClass('none');
                            // 切换分支为显示状态 - （注意：原本是放在插入后的）
                            //$branch.trigger('branch-onlychangedom');

                            // 增加一个节点
                            $originTBODY.append(function(){
                                return that._dom.createChildren.call(that, [childJsonData], nid, false);
                            });
                            // 增加一个行合并
                            $originTRTwoTDs.prop('rowspan', function(i, rowspan){
                                if (i == 1 && rowspan == 1) {
                                    $(this).children('div').removeClass('none');
                                };
                                return rowspan + 1;
                            });
                            // 修复关系链样式类名
                            that._repairDepClassName($targetTR);
                            // 切换分支为显示状态 - （注意：换到添加之前）
                            // 重新显示菜单
                            //that._delegation.showMenu.call(that, $node);
                        }
                        else{
                            $node.replaceWith(function() {
                                var $name = $node.children('span[data-type="name"]'),
                                    $icon = $node.children('i[data-type="icon"]'),
                                    level = Number($node.attr('data-level') || 0),
                                    pnid = Number($node.attr('data-pid') || 0);
                                return that._dom.createOrigin.call(that, {
                                    id: nid,
                                    name: $.trim($name.text()),
                                    level: level,
                                    icon: ($icon.children('img').attr('src') || ''),
                                    children: [childJsonData]
                                }, pnid);
                            });
                            // 重新获取节点，在重新显示菜单
                            $node = that._dom.getBox.call(that, nid);
                            // 如果使用此段代码，在节点靠近右侧时，操作新增功能，会出现父节点菜单不会隐藏现象
                            // that._delegation.showMenu.call(that, $node);
                        }
                        // 更新JsonData
                        that._data.add.call(that, nid, childJsonData, null, false);
                        // 重新绑定拖拽事件
                        that._event.onDragDrop.call(that);
                        // 更改节点为可编辑状态
                        //that._delegation.edit.call(that, childJsonData.id);
                    });
                },
                update: function($node, $input, defname, iscancel){
                    var that = this,
                        commitFN = (this.options.CallBack || {}).commitFN || function(){},
                        updateNameFN = (this.options.CallBack || {}).updateNameFN || function(){},
                        nid = Number($node.attr('data-id') || 0),
                        inpname = $.trim($input.val()) || defname,
                        updateDOMFN = function(name){
                            $node.removeAttr('data-status');// 更改节点状态
                            $input.replaceWith(function(){
                                return that._dom.createName.call(that, name);
                            });
                        },
                        successFN = function(){
                            updateDOMFN(inpname);
                            // 更新JsonData
                            that._data.updateName.call(that, nid, inpname, null);
                            successFN = function(){};
                        },
                        errorFN = function(){
                            updateDOMFN(defname);
                            errorFN = function(){};
                        }

                    if(!iscancel){
                        // 执行提交模拟操作委托函数
                        commitFN.call(that, nid, function cloneJsonData(){
                            var _cloneJsonData = {};
                            // 深度拷贝 JsonData
                            _cloneJsonData = $.extend(true, {}, that.options.jsonData);
                            // 更新 JsonData
                            that._data.updateName.call(that, nid, inpname, _cloneJsonData);
                            // 返回克隆已更新数据
                            return _cloneJsonData;
                        }, successFN, errorFN);
                        // 执行更新节点名称委托函数
                        updateNameFN.call(that, nid, inpname, successFN, errorFN);
                    }
                    else{
                        updateDOMFN(defname);
                    }
                },
                edit: function(nid){
                    var that = this,
                        $mindmap = that.dom.mindmap,
                        $node = that._dom.getBox.call(that, nid),
                        $menu = $node.children('div[data-type="menu"]'),
                        $iconList = $node.children('div[data-type="icon-list"]'),
                        $name = $node.children('span[data-type="name"]'),
                        defname = $.trim($name.text()),
                        nameWidth = $name.width(),
                        $input = $('<input class="box-input" style="width: '+ (nameWidth - 8) +'px;" value="'+ defname +'" />');

                    $menu.add($iconList).remove();
                    $node.attr('data-status', 'edit');// 更改节点状态
                    $name.replaceWith($input);// 替换节点内容
                    $input// 绑定编辑框事件
                        .on('keydown', function(event){
                            // ENTER
                            if(event.keyCode == 13){
                                that._delegation
                                .update.call(that, $node, $input, defname, false);
                            }
                            // ESC
                            else if(event.keyCode == 27){
                                that._delegation
                                .update.call(that, $node, $input, defname, true);
                            }
                        })
                        .on('blur', function(){
                            that._delegation
                            .update.call(that, $node, $input, defname, false);
                        })
                        .focus()
                        .select();
                },
                remove: function(nid){
                    var that = this,
                        //nid = Number($del.parent('div').attr('data-nid') || 0),
                        $mindmap = that.dom.mindmap,
                        $node = that._dom.getBox.call(that, nid),
                        pnid = Number($node.attr('data-pid') || 0),
                        commitFN = (this.options.CallBack || {}).commitFN || function(){},
                        removeFN = (this.options.CallBack || {}).removeFN || function(){},
                        successFN = function(){
                            var $targetTR = that._dom.getTargetTR.call(that, $node),// 准删除目标节点
                                $originTR = $targetTR.prevAll('tr[data-type="origin"]'), // 准删除目标节点的源节点
                                $originTRTwoTDs = $originTR.children('td').slice(0, 2);// 源节点的前两个子节点

                            $targetTR.attr('data-status', 'unavailable');// 标识准删除目标节点为不可用节点
                            // 修复关系链样式类名
                            that._repairDepClassName($targetTR);
                            // 减少一个行合并
                            $originTRTwoTDs.prop('rowspan', function(i, rowspan){
                                if (i == 1 && rowspan == 2) {
                                    $(this).children('div').addClass('none');
                                };
                                return rowspan > 1 ? rowspan - 1 : 1;
                            });
                            // 移除准删除目标节点
                            $targetTR.remove();
                            // 更新JsonData
                            that._data.remove.call(that, nid, null);
                            successFN = function(){};
                        };
                    // 判断根节点，如果节点为根节点，则不能上下移动
                    if(pnid !== 0){
                        // 执行提交模拟操作委托函数
                        commitFN.call(that, nid, function cloneJsonData(){
                            // 深度拷贝 JsonData
                            var _cloneJsonData = $.extend(true, {}, that.options.jsonData);
                            // 更新 JsonData
                            that._data.remove.call(that, nid, _cloneJsonData);
                            // 返回克隆已更新数据
                            return _cloneJsonData;
                        }, successFN);

                        // 执行删除节点委托函数
                        removeFN.call(that, nid, successFN);
                    }
                },
                switchMove: function(nid, dataType){
                    var that = this,
                        //dataType = $move.attr('data-type'),
                        //nid = Number($move.parent('div').attr('data-nid') || 0),
                        $mindmap = that.dom.mindmap,
                        $node = that._dom.getBox.call(that, nid),
                        pnid = Number($node.attr('data-pid') || 0),
                        commitFN = (this.options.CallBack || {}).commitFN || function(){},
                        updateIndexFN = (this.options.CallBack || {}).updateIndexFN || function(){};

                    // 判断根节点，如果节点为根节点，则不能上下移动
                    if (pnid !== 0) {
                        var $targetTR = that._dom.getTargetTR.call(that, $node),// 准移动目标节点
                            $targetPrevTR = $targetTR.prev('tr'),// 准移动目标节点的上一个节点
                            nindex = $targetTR.index() - 1,
                            continuedFN = function(){
                                // 隐藏菜单
                                that._delegation.hideMenuIcon.call(that, $node);
                                // 修复关系链样式类名
                                that._repairDepClassName($targetTR);
                            },
                            successFN = function(){};
                        // 判断是否不为第一个子节点，则切换上移功能
                        if (dataType == 'move-up' && !!$targetPrevTR.length && !$targetPrevTR._isorigin()) {
                            successFN = function(){
                                // 准移动目标节点后插入前面的一个节点
                                $targetTR.after($targetPrevTR);
                                // 待完成委托函数
                                continuedFN();
                                // 更新JsonData
                                that._data.move.call(that, nid, true, null);
                                successFN = function(){};
                            };
                            // 执行提交模拟操作委托函数
                            commitFN.call(that, nid, function cloneJsonData(){
                                // 深度拷贝 JsonData
                                var _cloneJsonData = $.extend(true, {}, that.options.jsonData);
                                // 更新 JsonData
                                that._data.move.call(that, nid, true, _cloneJsonData);
                                // 返回克隆已更新数据
                                return _cloneJsonData;
                            }, successFN);
                            // 执行更新节点顺序委托函数
                            updateIndexFN.call(that, nid, nindex, true, successFN);
                        };

                        var $targetNextTR = $targetTR.next('tr');// 准移动目标节点的下一个节点
                        // 判断是否不为最后一个子节点，则切换下移功能
                        if (dataType == 'move-down' && !!$targetNextTR.length) {
                            successFN = function(){
                                // 准移动目标节点前插入后面的一个节点
                                $targetTR.before($targetNextTR);
                                // 待完成委托函数
                                continuedFN();
                                // 更新JsonData
                                that._data.move.call(that, nid, false, null);
                                successFN = function(){};
                            };
                            // 执行提交模拟操作委托函数
                            commitFN.call(that, nid, function cloneJsonData(){
                                // 深度拷贝 JsonData
                                var _cloneJsonData = $.extend(true, {}, that.options.jsonData);
                                // 更新 JsonData
                                that._data.move.call(that, nid, false, _cloneJsonData);
                                // 返回克隆已更新数据
                                return _cloneJsonData;
                            }, successFN);
                            // 执行更新节点顺序委托函数
                            updateIndexFN.call(that, nid, nindex, false, successFN);
                        };
                    };
                },
                dragDrop: function($targetNode, $sourceNode){
                    var that = this,
                        $targetTR = $targetNode.parent('td').parent('tr'),
                        $sourceTR = that._dom.getTargetTR.call(that, $sourceNode),
                        $hiddenTR = $targetTR._ishidden() ? $targetTR : $targetTR.parentsUntil('tr.hidden').last('td').parent('tr'),
                        targetNID = Number($targetNode.attr('data-id') || 0),
                        sourceNID = Number($sourceNode.attr('data-id') || 0),
                        sourceJsonDataFN = function(){
                            return that._data.get.call(that, sourceNID, null).jsonData;
                        },
                        commitFN = (this.options.CallBack || {}).commitFN || function(){},
                        updatePNIDFN = (that.options.CallBack || {}).updatePNIDFN || function(){},
                        successFN = function(){
                            // 判断目标节点是否为源节点
                            if($targetTR._isorigin()){
                                var $targetOriginTR = $targetTR,// 准目标源节点
                                    $targetOriginTRTwoTDs = $targetOriginTR.children('td').slice(0, 2),
                                    $targetOriginTBODY = $targetOriginTR.parent('tbody'),//源节点的父节点
                                    $originTRTwoTDs = $targetOriginTR.children('td').slice(0, 2),// 源节点的前两个子节点
                                    $branch = $originTRTwoTDs.eq(1).find('i[data-type="branch"][data-value="1"]');
                                
                                // 切换分支为显示状态 - （注意：原本是放在插入后的）
                                $branch.trigger('branch-onlychangedom');

                                // 增加一个节点
                                $targetOriginTBODY.append(function(){
                                    return that._dom.createChildren.call(that, [sourceJsonDataFN()], targetNID, false);
                                });
                                // 修复目标节点关系链样式类名
                                that._repairDepClassName($targetTR);
                                // 增加一个行合并
                                $targetOriginTRTwoTDs.prop('rowspan', function(i, rowspan){
                                    if (i == 1 && rowspan == 1) {
                                        $(this).children('div').removeClass('none');
                                    };
                                    return rowspan + 1;
                                });
                                // 切换分支为显示状态 - （注意：换到添加之前）
                            }
                            else{
                                $targetNode.replaceWith(function() {
                                    var $targetName = $targetNode.children('span[data-type="name"]'),
                                        $targetIcon = $targetNode.children('i[data-type="icon"]'),
                                        targetPNID = Number($targetNode.attr('data-pid') || 0);
                                    return that._dom.createOrigin.call(that, {
                                        id: targetNID,
                                        name: $.trim($targetName.text()),
                                        icon: ($targetIcon.children('img').attr('src') || ''),
                                        children: [sourceJsonDataFN()]
                                    }, targetPNID);
                                });
                            }
                            
                            $sourceTR.attr('data-status', 'unavailable');// 标识准删除源节点为不可用节点
                            that._repairDepClassName($sourceTR);// 修复源节点关系链样式类名
                            
                            var $sourceOriginTR = $sourceTR.prevAll('tr[data-type="origin"]'),
                                $sourceOriginTRTwoTDs = $sourceOriginTR.children('td').slice(0, 2);
                            // 减少一个行合并
                            $sourceOriginTRTwoTDs.prop('rowspan', function(i, rowspan){
                                if (i == 1 && rowspan == 2) {
                                    $(this).children('div').addClass('none');
                                };
                                return rowspan > 1 ? rowspan - 1 : 1;
                            });
                            // 更新JsonData
                            that._data.dragDrop.call(that, sourceNID, targetNID, null, false);
                            successFN = function(){};
                        };

                    if ($hiddenTR.length > 0) {
                        return false;
                    };

                    // 执行提交模拟操作委托函数
                    commitFN.call(that, targetNID, function cloneJsonData(){
                        // 深度拷贝 JsonData
                        var _cloneJsonData = $.extend(true, {}, that.options.jsonData);
                        // 更新 JsonData
                        that._data.dragDrop.call(that, sourceNID, targetNID, _cloneJsonData, false);
                        // 返回克隆已更新数据
                        return _cloneJsonData;
                    }, successFN);
                    // 执行更新节点顺序委托函数
                    updatePNIDFN.call(that, sourceNID, targetNID, successFN);
                }
            },
            _dom: {
                createViewIcon: function(viewIcon){
                    if(typeof viewIcon === 'string' && $.trim(viewIcon) !== ''){
                        return '<div class="box-view-icon"><img src="'+ viewIcon +'"/></div>';
                    }
                    return '';
                },
                createIcon: function(icon){
                    return '';
                    if (typeof icon === 'string' && $.trim(icon) !== '') {
                        return '<i class="box-icon" data-type="icon"><img src="'+ icon +'"/></i>';
                    }
                    else{
                        return '<i class="box-icon" data-type="icon"></i>';
                    }
                },
                createName: function(name){
                    var className = this.options.isAutoWidth ? 'box-text nowrap' : 'box-text ellipsis';
                    return '<span class="'+ className +'" '+
                            'data-type="name" '+
                            'title="'+ (name || '') +'">'+ (name || '') +'</span>';
                },
                createBtn: function(nodeJson){
                    if (nodeJson.level == 'department') {
                        return '';
                    }
                    return '<span class="box-set"></span><span class="box-add"></span>';
                },
                createBox: function(nodeJson, pid, hasChildren){
                    var skinName = nodeJson.level ? ('box-skin-' + nodeJson.level) : '',
                        manager = nodeJson.manager || {},
                        fullName = nodeJson.name +  (manager.name ? (' (' + manager.name + ')') : '');

                    return '<div class="node-box ellipsis box-skin '+ skinName +'" '+
                                'data-type="node" '+
                                'data-haschildren="'+ (hasChildren ? 'true' : 'false') +'" '+
                                'data-id="'+ (nodeJson.id || 0) +'" '+
                                'data-level="'+ (nodeJson.level || 0) +'" '+
                                'data-pid="'+ (pid || 0) +'">'+ 
                                (this._dom.createIcon.call(this, nodeJson.icon)) +
                                (this._dom.createName.call(this, fullName)) +
                                (this._dom.createBtn.call(this, nodeJson)) +
                            '</div>'+
                            (function(that){
                                if(that.options.isView && !hasChildren){
                                    return that._dom.createViewIcon.call(that, nodeJson.viewIcon);
                                }
                                else{
                                    return '';
                                }
                            }(this)) + 
                            '<div class="clear"></div>';
                },
                createBranch: function(nodeJson, hasChildren){
                    // 只有一个子集
                    var oneChildren = nodeJson.children && nodeJson.children.length === 1,
                        className = '';

                    if (hasChildren) {
                        className = oneChildren ? 'none' : '';
                    }
                    else{
                        className = 'none';
                    }

                    return ['<div class="node-branch'+ ' ' + className +'">',
                                (function(){
                                    return '<i class="line"></i>';

                                    if (!!nodeJson.collapsed) {
                                        return '<i class="collapsed" data-type="branch" data-value="1"></i>';
                                    }
                                    else{
                                        return '<i class="expand" data-type="branch" data-value="0"></i>';
                                    }
                                }()),
                            '</div>'].join('');
                },
                createChildren: function(nodeArray, pid, pcollapsed){
                    var that = this;
                    return $.map(nodeArray, function(nodeJson, index){
                        return ['<tr'+ (pcollapsed ? ' class="hidden"' : '') +'>',
                                    '<td class="'+ that._getDepClassName(index, nodeArray.length) +'"></td>',
                                    '<td>',
                                        (function(nodeJson){
                                            // 该节点存在子节点，则调用源节点函数
                                            if(!!nodeJson.children && nodeJson.children.length > 0){
                                                return that._dom.createOrigin.call(that, nodeJson, pid);
                                            }
                                            // 没有子节点，则调用盒节点函数
                                            else{
                                                return that._dom.createBox.call(that, nodeJson, pid, false);
                                            }
                                        }(nodeJson)),
                                    '</td>',
                                '</tr>'].join('');
                    }).join('');
                },
                createOrigin: function(nodeJson, pid){
                    var that = this,
                        children = nodeJson.children || [],
                        rowspan = children.length + 1,
                        hasChildren = children.length > 0;
                    return ['<table>',
                                '<tbody>',
                                    '<tr data-type="origin">',
                                        '<td rowspan="'+ rowspan +'">',
                                            (function(){
                                                return that._dom.createBox.call(that, nodeJson, pid, hasChildren);
                                            }()),
                                        '</td>',
                                        '<td rowspan="'+ rowspan +'">',
                                            (function(){
                                                return that._dom.createBranch.call(that, nodeJson, hasChildren);
                                            }()),
                                        '</td>',
                                        '<td></td>',
                                        '<td></td>',
                                    '</tr>',
                                    (function(){
                                        if (hasChildren) {
                                            return that._dom.createChildren.call(that, children, nodeJson.id, nodeJson.collapsed);
                                        }
                                        return '';
                                    }()),
                                '</tbody>',
                            '</table>'].join('');
                },
                createMindMap: function(nodeJson){
                    var that = this;
                    return ['<div class="mindmap">',
                                (function(){
                                    return that._dom.createOrigin.call(that, nodeJson, null);
                                }()),
                            '</div>'].join('');
                },
                createMenu: function($node){
                    var that = this,
                        nid = Number($node.attr('data-id') || 0),
                        pnid = Number($node.attr('data-pid') || 0),
                        _html = [],
                        _menu = {
                            general: ['icon', 'add', 'edit'],
                            special: ['del'],
                            move: ['move-up', 'move-down']
                        },
                        _getOne = function(menu){
                            return '<i class="'+ menu +'" title="'+ (MINDMAP_MENU_TITLE[menu] || '') +'" data-type="'+ menu +'"></i>';
                        };

                    // 菜单的 div 开始标签
                    _html.push('<div class="node-menu" data-type="menu">');

                    // 添加常用功能
                    $.each(_menu.general, function(i, menu){
                        _html.push(_getOne(menu));
                    });

                    // 判断根节点，如果节点为根节点，则不能删除、上下移动
                    if (pnid !== 0) {
                        // 删除功能
                        _html.push(_getOne(_menu.special[0]));

                        // 上下移动功能
                        var $targetTR = that._dom.getTargetTR.call(that, $node),// 准移动目标节点
                            $targetPrevTR = $targetTR.prev('tr');// 准移动目标节点的上一个节点
                        // 判断是否不为第一个子节点，则附加上移功能
                        if (!!$targetPrevTR.length && !$targetPrevTR._isorigin()) {
                            _html.push(_getOne(_menu.move[0]));
                        };

                        var $targetNextTR = $targetTR.next('tr');// 准移动目标节点的下一个节点
                        // 判断是否不为最后一个子节点，则附加下移功能
                        if (!!$targetNextTR.length) {
                            _html.push(_getOne(_menu.move[1]));
                        };
                    };

                    // 菜单的 div 结束标签
                    _html.push('</div>');

                    // 转为 jQuery 对象
                    return $(_html.join('')).attr('data-nid', nid);
                },
                getBox: function(nid){
                    return $('div[data-id="'+ nid +'"][data-type="node"]', this.dom.mindmap);
                },
                getTargetTR: function($node){
                    var $targetTR = $node.parent('td').parent('tr');// 准目标节点
                            
                    // 判断是否为源节点，如果是则往DOM父节点数查找
                    if ($targetTR._isorigin()) {
                        $targetTR = $targetTR.parentsUntil('tr').last('td').parent();
                    };
                    return $targetTR;
                }
            },
            _data:{
                /**
                 * 通过一个节点获取节点信息和子节点集合
                 * @param  {[Number]} nid      [节点ID]
                 * @param  {[Object]} jsonData [节点树，值可为NULL]
                 * @return {[Object]}          [节点ID相关的节点树]
                 */
                get: function(nid, jsonData){
                    var that = this,
                        jsonData = jsonData || that.options.jsonData || {},
                        jsonArray = jsonData.children || [],
                        jsonObject = {
                            pJsonArray: null,
                            jsonData: jsonData,
                            jsonIndex: -1
                        };

                    // 重置collapsed为布尔型
                    if (typeof jsonData.collapsed == 'string') {
                        jsonData.collapsed = Number(jsonData.collapsed)
                    };
                    jsonData.collapsed = !!jsonData.collapsed;
                    // 重置id为数字型
                    if (typeof jsonData.id === 'string' && jsonData.id != 'department') {
                        jsonData.id = Number(jsonData.id);
                    };
                    if (jsonData.id !== Number(nid)) {
                        var _jsonObject = null;
                        // 遍历节点下的子节点集合
                        $.each(jsonArray, function(index, _jsonData){
                            // 获取每个子节点数据
                            _jsonObject = that._data.get.call(that, nid, _jsonData);
                            // 判断子节点数据是否读取
                            if(_jsonObject !== null){
                                // 判断子节点索引是否存在
                                if (_jsonObject.jsonIndex == -1) {
                                    // 重新整理新的节点数据
                                    _jsonObject = {
                                        pJsonArray: jsonArray,
                                        jsonData: _jsonData,
                                        jsonIndex: index
                                    };
                                };
                                return false;
                            }
                        });
                        return _jsonObject;
                    }
                    else{
                        return jsonObject;
                    }
                },
                /**
                 * 添加一个节点的子节点
                 * @param {[Number]}  nid             [节点ID]
                 * @param {[Object]}  childJsonData   [子节点数据]
                 * @param {[Object]}  jsonData        [节点树，值可为NULL]
                 * @param {[Boolean]} iscollapsed     [节点折叠状态，值可为NULL]
                 */
                add: function(nid, childJsonData, jsonData, iscollapsed){
                    var that = this,
                        jsonObject = this._data.get.call(this, nid, jsonData) || {},
                        jsonData = jsonObject.jsonData || {};

                    if (typeof iscollapsed === 'boolean') {
                        jsonData.collapsed = iscollapsed;
                    };
                    jsonData.children = jsonData.children || [];
                    jsonData.children.push(childJsonData);
                    return jsonData;
                },
                /**
                 * 移除一个节点，包括子节点
                 * @param  {[Number]} nid [节点ID]
                 * @param  {[Object]} jsonData [节点树，值可为NULL]
                 */
                remove: function(nid, jsonData){
                    var that = this,
                        jsonObject = this._data.get.call(this, nid, jsonData) || {},
                        pJsonArray = jsonObject.pJsonArray || [],
                        jsonIndex = jsonObject.jsonIndex;

                    return pJsonArray.splice(jsonIndex, 1)[0];
                },
                /**
                 * 上下移动节点
                 * @param  {[Number]}  nid      [节点ID]
                 * @param  {[Boolean]} ismoveup [是否向上移动]
                 * @param  {[Object]}  jsonData [节点树，值可为NULL]
                 */
                move: function(nid, ismoveup, jsonData){
                    var that = this,
                        jsonObject = this._data.get.call(this, nid, jsonData) || {},
                        pJsonArray = jsonObject.pJsonArray || [],
                        jsonData = jsonObject.jsonData|| {},
                        jsonIndex = jsonObject.jsonIndex,
                        tempJsonData = null;

                    if (!!ismoveup && jsonIndex > 0) {
                        tempJsonData = pJsonArray.splice(jsonIndex, 1);
                        pJsonArray.splice(jsonIndex - 1, 0, tempJsonData[0]);
                    }
                    else if(jsonIndex < pJsonArray.length - 1){
                        tempJsonData = pJsonArray.splice(jsonIndex + 1, 1);
                        pJsonArray.splice(jsonIndex, 0, tempJsonData[0]);
                    }
                },
                /**
                 * 拖拽节点
                 * @param  {[Number]}  sourceNID    [源节点ID]
                 * @param  {[Number]}  targetNID    [目标节点ID]
                 * @param  {[Object]}  jsonData     [节点树，值可为NULL]
                 * @param  {[Boolean]} iscollapsed  [节点折叠状态，值可为NULL]
                 */
                dragDrop: function(sourceNID, targetNID, jsonData, iscollapsed){
                    var that = this,
                        childJsonData = that._data.remove.call(that, sourceNID, jsonData);

                    that._data.add.call(that, targetNID, childJsonData, jsonData, iscollapsed);
                },
                /**
                 * 更改节点名称
                 * @param  {[Number]} nid      [节点ID]
                 * @param  {[String]} newname  [新节点名称]
                 * @return {[Object]} jsonData [节点树，值可为NULL]
                 */
                updateName: function(nid, newname, jsonData){
                    var that = this,
                        jsonObject = this._data.get.call(this, nid, jsonData) || {},
                        jsonData = jsonObject.jsonData || {};

                    jsonData.name = newname;
                },
                /**
                 * 更改节点图标
                 * @param  {[Number]} nid      [节点ID]
                 * @param  {[String]} newname  [新节点图标]
                 * @return {[Object]} jsonData [节点树，值可为NULL]
                 */
                updateIcon: function(nid, newicon, jsonData){
                    var that = this,
                        jsonObject = this._data.get.call(this, nid, jsonData) || {},
                        jsonData = jsonObject.jsonData || {};

                    jsonData.icon = newicon;
                },
                /**
                 * 更改节点折叠状态
                 * @param  {[Number]}  nid            [节点ID]
                 * @param  {[Boolean]} newiscollapsed [新折叠状态]
                 * @return {[Object]}  jsonData       [节点树，值可为NULL]
                 */
                updateCollapsed: function(nid, newiscollapsed, jsonData){
                    var that = this,
                        jsonObject = this._data.get.call(this, nid, jsonData) || {},
                        jsonData = jsonObject.jsonData || {};

                    jsonData.collapsed = !!newiscollapsed;
                }
            },
            // 获取关系链样式类名
            _getDepClassName: function(index, totalLength){
                if (totalLength == 1) {
                    return 'dep dep-line';
                }
                else if(index == 0){
                    return 'dep dep-top'
                }
                else if(index == totalLength - 1){
                    return 'dep dep-bom';
                }
                else{
                    return 'dep dep-mid';
                }
            },
            // 修复关系链样式类名
            _repairDepClassName: function($targetTR){
                var that = this,
                    $targetTRs = $targetTR.parent('tbody').children('tr[data-type!="origin"][data-status!="unavailable"]'),// 非源节点 TR 集合
                    $targetTRFirstTDs = $targetTRs.children('td:first-child');// 非源节点 TR 内第一个子节点 TD 集合
                
                // 遍历更新关系链样式类名
                $targetTRFirstTDs.each(function(index){
                    $(this).removeClass().addClass(function(){
                        return that._getDepClassName(index, $targetTRFirstTDs.length);
                    });
                });
            },
            render: function(){
                var that = this,
                    jsonData = that.options.jsonData || {},
                    $mindmap = $(that._dom.createMindMap.call(that, jsonData));
                    
                // 判断是否不存在 jQuery 对象
                if (that.dom.mindmap === null) {
                    $mindmap.appendTo(that.dom.container);
                }
                else{
                    $mindmap.replaceAll(that.dom.mindmap);
                }
                that.dom.mindmap = $mindmap;
                // 初始化事件
                that._event.init.call(that);
            }
        };

        /* 思维导图默认配置选项 */
        mindmap.defaults = {
            jsonData: null,
            isView: true,
            Template: {
                iconList: '<div class="node-icon-list">未定义图标模板</div>'
            },
            CallBack: {
                // 编辑模式-添加一个子节点的接口函数
                addFN: function(nid, successFN){
                    this._tempData = this._tempData || {};
                    this._tempData.addNodeNum = this._tempData.addNodeNum || 0;
                    successFN && successFN(nid, {
                        "id": Math.random(),
                        "name": "new node - " + (this._tempData.addNodeNum += 1)
                    });
                },
                // 编辑模式-移除一个节点的接口函数
                removeFN: function(nid, successFN){
                    successFN && successFN(nid);
                },
                // 编辑模式-更新一个节点的顺序的接口函数
                updateIndexFN: function(nid, nindex, ismoveup, successFN){
                    successFN && successFN(nid);
                },
                // 编辑模式-更新一个节点的父节点ID的接口函数
                updatePNIDFN: function(nid, newpnid, successFN){
                    successFN && successFN(nid);
                },
                // 编辑模式-更新一个节点的节点名称的接口函数
                updateNameFN: function(nid, newname, successFN, errorFN){
                    successFN && successFN(nid);
                },
                // 编辑模式-更新一个节点的节点图标的接口函数
                updateIconFN: function(nid, newicon, successFN){
                    successFN && successFN(nid);
                },
                // 编辑模式-更新一个节点的展开或折叠的接口函数
                updateCollapsedFN: function(nid, newiscollapsed, successFN){
                    successFN && successFN(nid);
                },
                // 编辑模式-提交数据的接口函数，常用于移除节点；修改节点名称、索引、图标、折叠状态、父节点ID
                commitFN: function(nid, cloneJsonData, successFN){}
            },
            Event: {
                // 预览模式-点击最后一级节点触发事件
                endViewFN: function(nid, jsonData){}
            },
            isAutoWidth: true
        };

        /* 思维导图 jQuery 扩展函数 */
        $.fn.extend({
            mindmap: function(){
                var args = arguments;
                return $(this).map(function(){
                    if (args.length === 1) {
                        var arg1 = args[0],
                            that = $(this).data('data-mindmap') || null;
                        if (that !== null && typeof arg1 === 'string' && typeof that[arg1] === 'function') {
                            that[arg1].call(that);
                        }
                        else if(typeof arg1 === 'object'){
                            new mindmap(this, arg1);
                        }
                    }
                    return this;
                });
            },
            _isorigin: function(){
                return $(this).attr('data-type') === 'origin';
            },
            _ishidden: function(){
                return $(this).hasClass('hidden');
            }
        });
    });
}(jQuery172));